package com.hospital.search.module.utils;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hospital.common.dto.search.module.PostInsertDto;
import com.hospital.common.dto.search.module.ReplyInsertDto;
import com.hospital.common.pojo.TPostContent;
import com.hospital.common.pojo.TSection;
import com.hospital.common.pojo.TUser;
import com.hospital.common.utils.LocalDateTimeUtils;
import com.hospital.search.module.base.annotation.EnablePostInsertVerify;
import com.hospital.search.module.base.annotation.EnableReplyInsertVerify;
import com.hospital.search.module.exception.SearchServiceException;
import com.hospital.search.module.exception.enums.SearchServiceExpCode;
import com.hospital.search.module.index.PostIndex;
import com.hospital.search.module.service.TPostContentService;
import com.hospital.search.module.service.TSectionService;
import com.hospital.search.module.service.TUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
public class ElasticInsertUtils {
    @Value("${elastic.index-alias}")
    private String indexAlias;
    @Autowired
    private TSectionService sectionService;
    @Autowired
    private TUserService userService;
    @Autowired
    private TPostContentService postContentService;
    private final ElasticsearchClient esClient;
    public ElasticInsertUtils(ElasticsearchClient esClient) {
        this.esClient = esClient;
    }
    @EnablePostInsertVerify
    public void insertPost(PostInsertDto insertDto){
        PostIndex postIndex = new PostIndex();
        copy(insertDto, postIndex);
        try {
            esClient.index(i->i.index(indexAlias)
                    .document(postIndex));
        } catch (IOException e) {
            throw new SearchServiceException(SearchServiceExpCode.INSERT_POST_ERROR);
        }
    }
    private void copy(PostInsertDto insertDto,PostIndex postIndex){
        TSection section = sectionService.getById(insertDto.getSectionId());
        String sectionName = ObjectUtils.isEmpty( section)? "未知板块" : section.getName();
        TUser user = userService.getById(insertDto.getAuthorId());
        String author = ObjectUtils.isEmpty(user)? "未知作者" : user.getName();
        LambdaQueryWrapper<TPostContent> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TPostContent::getMetaId,insertDto.getMetaId())
                                .select(TPostContent::getText);
        List<String> postContentList = postContentService.list(queryWrapper).stream().map(TPostContent::getText).toList();
        postIndex.setContent(StringUtils.join(postContentList, ""));
        postIndex.setMetaId(insertDto.getMetaId());
        postIndex.setSectionId(insertDto.getSectionId());
        postIndex.setAuthorId(insertDto.getAuthorId());
        postIndex.setTitle(insertDto.getTitle());
        postIndex.setAbstracts(insertDto.getAbstracts());
        postIndex.setIsTop(insertDto.getIsTop());
        postIndex.setIsPinned(insertDto.getIsPinned());
        postIndex.setLikeCount(insertDto.getLikeCount());
        postIndex.setReplyCount(insertDto.getReplyCount());
        postIndex.setFavoriteCount(insertDto.getFavoriteCount());
        postIndex.setHeatScore(insertDto.getHeatScore());
        postIndex.setFirstAttachmentUrl(insertDto.getFirstAttachmentUrl());
        postIndex.setCreateTime(LocalDateTimeUtils.toEpochMillis(insertDto.getCreateTime()));
        postIndex.setUpdateTime(LocalDateTimeUtils.toEpochMillis(insertDto.getUpdateTime()));
        postIndex.setSectionName(sectionName);
        postIndex.setAuthor(author);
        postIndex.setAuthorRole(insertDto.getAuthorRole());
    }
    @EnableReplyInsertVerify
    public void insertReply(ReplyInsertDto insertDto){
        SearchResponse<PostIndex> searchResponse = null;
        try {
            searchResponse = esClient.search(s -> s
                            .index(indexAlias)
                            .query(q -> q
                                    .term(t -> t
                                            .field("metaId")
                                            .value(insertDto.getMetaId())
                                    )
                            ),
                    PostIndex.class
            );
        } catch (IOException e) {
            throw new SearchServiceException(SearchServiceExpCode.SEARCH_SERVICE_ERROR);
        }
        Optional<Hit<PostIndex>> postIndexHitOptional = searchResponse.hits().hits().stream().findFirst();
        postIndexHitOptional.ifPresent(postIndexHit -> {
            try {
                esClient.update(
                        u -> u.id(postIndexHit.id())
                                .index(indexAlias)
                                .doc(Map.of(
                                        "replyCount", ObjectUtils.isEmpty(postIndexHit.source()) ? 1 : postIndexHit.source().getReplyCount() + 1,
                                        "updateTime", LocalDateTimeUtils.toEpochMillis(LocalDateTime.now()),
                                        "content", ObjectUtils.isEmpty(postIndexHit.source()) ? insertDto.getText() : postIndexHit.source().getContent() + insertDto.getText()
                                )),
                        PostIndex.class
                );
            } catch (IOException e) {
                throw new SearchServiceException(SearchServiceExpCode.INSERT_REPLY_ERROR);
            }
        });
    }
}
